package com.dmbjz.follow.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.dmbjz.common.constant.ApiConstant;
import com.dmbjz.common.constant.RedisKeyConstant;
import com.dmbjz.common.exception.ParameterException;
import com.dmbjz.common.model.domain.ResultInfo;
import com.dmbjz.common.model.entity.Follow;
import com.dmbjz.common.model.vo.ShortDinerInfo;
import com.dmbjz.common.model.vo.SingInDinerInfo;
import com.dmbjz.common.utils.AssertUtil;
import com.dmbjz.common.utils.ResultInfoUtil;
import com.dmbjz.follow.dao.FollowDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;


/*关注功能Service*/
@Service
@Transactional(rollbackFor = Exception.class)
public class FollowService {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${service.name.ms-oauth-service}")
    private String oauthServiceName;
    @Value("${service.name.ms-diner-service}")
    private String dinerServiceName;
    @Value("${service.name.ms-feed-service}")
    private String feedServiceName;
    @Autowired
    private FollowDao followDao;


    /*获取用户的粉丝列表*/
    public Set<Integer> findFollowers(Integer dinerId){

        AssertUtil.isNotNull(dinerId,"选择要查看的用户");
        Set<Integer> members = redisTemplate.opsForSet().members(RedisKeyConstant.followers.getKey() + dinerId);
        return members;

    }

    /*共同关注列表*/
    public ResultInfo findCommonsFriends(Integer dinersId,String accessToken,String path){

        /*是否选择了关注对象*/
        AssertUtil.isTrue(dinersId==null || dinersId<1,"请选择需要查看的人");

        /*获取登录用户信息*/
        SingInDinerInfo dinerInfo = loadSignInDinerInfo(accessToken);
        /*获取登录用户关注信息*/
        String loginDinerKey = RedisKeyConstant.following.getKey()+dinerInfo.getId();
        /*获取目标用户的关注信息*/
        String selectDinerKey = RedisKeyConstant.following.getKey()+dinersId;
        /*计算交集*/
        Set<Integer> interIds = redisTemplate.opsForSet().intersect(loginDinerKey, selectDinerKey);

        /*判断交集是否存在,不存在返回空List，存在返回用户信息*/
        if(CollectionUtil.isEmpty(interIds)){
            return ResultInfoUtil.buildSuccess(path,new ArrayList<ShortDinerInfo>(1));
        }
        ResultInfo resultInfo = restTemplate.getForObject(dinerServiceName + "findByIds?&ids={ids}",
                ResultInfo.class,
                StrUtil.join(",", interIds));

        if(resultInfo.getCode()!=ApiConstant.SUCCESS_CODE){
            resultInfo.setPath(path);
            return  resultInfo;
        }
        List<ShortDinerInfo> dinerList = (List<ShortDinerInfo>) resultInfo.getData();//转为List
        return  ResultInfoUtil.buildSuccess(path,dinerList);

    }




    /*关注&取关操作
    *
    * followDinerId = 用户ID
    * isFollowed = 是否关注，1关注 & 0取消关注
    * accessToken = 用户登录Token
    * path = 访问地址
    */
    public ResultInfo follow(Integer followDinerId, int isFollowed, String accessToken, String path){

        /*是否选择关注对象*/
        AssertUtil.isTrue(followDinerId==null && followDinerId<1,"请选择需要关注的人");
        /*获取当前登录用户信息*/
        SingInDinerInfo dinerInfo = loadSignInDinerInfo(accessToken);

        /*获取当前登录用户与需要关注用户的关注信息*/
        Follow follow = followDao.selectFollow(dinerInfo.getId(), followDinerId);

        /*没有关注信息，添加关注并保存到Redis*/
        if(follow==null && isFollowed ==1){
            int save = followDao.save(dinerInfo.getId(), followDinerId);
            if(save==1){
                addToRedisSet(dinerInfo.getId(),followDinerId);
                sendSaveOrRemoveFeed(followDinerId,accessToken,1);
            }
            return ResultInfoUtil.build(ApiConstant.SUCCESS_CODE,"关注成功!",path,"关注成功!");
        }
        /*有关注信息&取关，重新关注*/
        if(follow!=null && follow.getIsValid()==0 && isFollowed ==1){
            int count = followDao.update(dinerInfo.getId(), followDinerId);
            if(count==1){
                addToRedisSet(dinerInfo.getId(),followDinerId);
                sendSaveOrRemoveFeed(followDinerId,accessToken,1);
            }
            return ResultInfoUtil.build(ApiConstant.SUCCESS_CODE,"关注成功!",path,"关注成功!");
        }
        /*有关注信息&关注，取消关注*/
        if(follow!=null && follow.getIsValid()==1 && isFollowed==0){
            int cancle = followDao.update(follow.getId(), isFollowed);
            if(cancle==1){
                removeFromRedisSet(follow.getId(),followDinerId);
                sendSaveOrRemoveFeed(followDinerId,accessToken,0);
            }
            return ResultInfoUtil.build(ApiConstant.SUCCESS_CODE,"取消关注成功!",path,"取消关注成功!");
        }

        return ResultInfoUtil.buildSuccess(path,"关注ERROR!");

    }



    /*移除关注*/
    private void removeFromRedisSet(Integer id, Integer followDinerId) {

        String userkey =  RedisKeyConstant.following.getKey()+ id;
        String followKey =  RedisKeyConstant.followers.getKey()+ followDinerId;
        redisTemplate.opsForSet().remove(userkey,followDinerId);//用户关注集合
        redisTemplate.opsForSet().remove(followKey,id);//被关注者的粉丝集合

    }
    /*添加关注*/
    private void addToRedisSet(Integer id, Integer followDinerId) {

        String userkey =  RedisKeyConstant.following.getKey()+ id;
        String followKey =  RedisKeyConstant.followers.getKey()+ followDinerId;
        redisTemplate.opsForSet().add(userkey,followDinerId);//用户关注集合
        redisTemplate.opsForSet().add(followKey,id);//被关注者的粉丝集合


    }
    /*发送请求添加或移除关注对象的Feeds*/
    private void sendSaveOrRemoveFeed(Integer followDinerId,String accessToken,int type){

        String feedsUpdateUrl = feedServiceName + "feeds/updateFollowingFeeds/"
                + followDinerId + "?access_token=" + accessToken;
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 构建请求体（请求参数）
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("type", type);
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
        restTemplate.postForEntity(feedsUpdateUrl, entity, ResultInfo.class);

    }




    /*获取登录信息*/
    private SingInDinerInfo loadSignInDinerInfo(String accessToken) {

        /*判断Token是否为空*/
        AssertUtil.mustLogin(accessToken);
        /*获取登录信息*/
        String url = oauthServiceName+"user/me?access_token={accessToken}";
        ResultInfo resultInfo = restTemplate.getForObject(url, ResultInfo.class, accessToken);
        if(resultInfo.getCode()!= ApiConstant.SUCCESS_CODE){
            throw new ParameterException(resultInfo.getMessage());
        }
        SingInDinerInfo dinerInfo = BeanUtil.fillBeanWithMap((LinkedHashMap)resultInfo.getData(),new SingInDinerInfo(),false);
        return dinerInfo;

    }


}
